/*
 * FFmpegSurfaceView.java
 * Copyright (c) 2012 Jacek Marchwicki
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.appunite.ffmpeg;

import com.appunite.ffmpeg.FFmpegPlayer.RenderedFrame;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;

public class FFmpegSurfaceView extends SurfaceView implements FFmpegDisplay,
		SurfaceHolder.Callback {

	private FFmpegPlayer mMpegPlayer = null;
	private Object mMpegPlayerLock = new Object();
	private TutorialThread mThread = null;
	static Rect mDstRect;
	private int mScreenWidth = 0;
	private int mScreenHeight = 0;
	
//	private Object mFpsCounterLock = new Object();
//	private FpsCounter mFpsCounter = null;

	public FFmpegSurfaceView(Context context) {
		this(context, null, 0);
	}

	public FFmpegSurfaceView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public FFmpegSurfaceView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		getHolder().addCallback(this);
        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        setFocusable(true);
        setFocusableInTouchMode(true);
        requestFocus();
	    requestLayout();
        invalidate();
	}

	@Override
	public void setMpegPlayer(FFmpegPlayer fFmpegPlayer) {
		if (mMpegPlayer != null)
			throw new RuntimeException("setMpegPlayer could not be called twice");
		
		synchronized (mMpegPlayerLock) {
			this.mMpegPlayer = fFmpegPlayer;
			mMpegPlayerLock.notifyAll();
		}
	}
	
/*	public void showFpsCounter(boolean showFpsCounter) {
		synchronized (mFpsCounterLock) {
			if (showFpsCounter) {
				if (mFpsCounter == null) {
					mFpsCounter = new FpsCounter(10);
				}
			} else {
				mFpsCounter = null;
			}
		}
	}
*/
	class TutorialThread extends Thread {
		private SurfaceHolder mSurfaceHolder;
		private boolean mRun = false;
		private int mSurfaceWidth;
		private int mSurfaceHeight;

		public TutorialThread(SurfaceHolder surfaceHolder) {
			mSurfaceHolder = surfaceHolder;
			mSurfaceHolder.setFixedSize(mSurfaceWidth, mSurfaceHeight);
		}

		public void setSurfaceParams(int width, int height) {
			mSurfaceHeight = height;
			mSurfaceWidth = width;
		}

		public synchronized void setRunning(boolean run) {
			mRun = run;
		}

		public synchronized boolean isRunning() {
			return mRun;
		}

		@Override
		public void run() {
			while (isRunning()) {
				try {
					synchronized (mMpegPlayerLock) {
						while (mMpegPlayerLock == null)
							mMpegPlayerLock.wait();
						renderFrame(mMpegPlayer);
					}
				} catch (InterruptedException e) {
				}
			}
		}

		private void renderFrame(FFmpegPlayer mpegPlayer) throws InterruptedException {
			RenderedFrame renderFrame = mpegPlayer.renderFrame();
			if (renderFrame == null)
				throw new RuntimeException();
			if (renderFrame.bitmap == null)
				throw new RuntimeException();
			try {
				drawFrame(renderFrame);
			} finally {
				mMpegPlayer.releaseFrame();							
			}
		}

		private void drawFrame(RenderedFrame renderFrame) {
			Canvas canvas = mSurfaceHolder.lockCanvas();
			if (canvas == null)
				return;
			try {
				canvas.drawColor(Color.BLACK);
				canvas.save();
			
	
			//	canvas.scale(ratio, ratio);
				canvas.drawBitmap(renderFrame.bitmap, null, mDstRect, null);
				canvas.restore();
			//	drawFpsCounter(canvas, moveX, moveY);
			} finally {
				mSurfaceHolder.unlockCanvasAndPost(canvas);
			}
		}

		/*private void drawFpsCounter(Canvas canvas, float moveX, float moveY) {
			synchronized (mFpsCounterLock) {
				if (mFpsCounter != null) {
					String fps = mFpsCounter.tick();
					canvas.drawText(fps, 40 - moveX, 40 - moveY, mPaint);
				}
			}
		}*/
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		surfaceDestroyed(holder);
		getHolder().setFixedSize(width, height);
		Log.d("playvideo","width is " + width + " height is " + height + " mScreenWidth is " + mScreenWidth + " mScreenHeight is " + mScreenHeight );
		
		if ( mDstRect == null ) {
			mDstRect = new Rect(); 
			mDstRect.set(0, 0, width, height);
		} 
		this.mMpegPlayer.renderFrameStart();
		mThread = new TutorialThread(getHolder());
		mThread.setRunning(true);
		mThread.setSurfaceParams(width, height);
		mThread.start();

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		if (mThread != null) {
			mThread.setRunning(false);
			this.mMpegPlayer.renderFrameStop();
			mThread.interrupt();
		}
	}

	public void setVideoScale(int screenWidth, int screenHeight) {
		/*mScreenWidth = screenWidth;
		mScreenHeight = screenHeight;
    	LayoutParams lp = getLayoutParams();
    	lp.height = screenHeight;
		lp.width = screenWidth;
		setLayoutParams(lp);
		getHolder().setFixedSize(screenWidth, screenHeight);*/
	}

}
